package com.wise.utils;

/**
 * redis分布工锁加锁工具
 */
public class DistributedLockUtil {
    private DistributedLockUtil(){
    }

    /**
     * redis加锁，个人建议这个方法如果是基于线程使用的话可以使用函数回调的方式进行修改
     * @param lockName
     * @return
     */
    //加锁：boolean lock(key,value):value一般为当前时间+设定过期时间（避免死锁）
    //lockName可以为共享变量名，也可以为方法名，主要是用于模拟锁信息 lockTime可以设置为System.currentTimeMillis+5000
    public static boolean lock(String lockName, long lockTime){
        System.out.println(Thread.currentThread() + "开始尝试加锁！");
        //如果没有锁存在，加锁返回true，即setnx（redisTemplate.setIfAbsent）
        Long result = RedisPoolUtil.setnx(lockName, String.valueOf(lockTime));
        if (result != null && result.intValue() == 1){
            System.out.println(Thread.currentThread() + "加锁成功！");
            RedisPoolUtil.expire(lockName, 5);
            System.out.println(Thread.currentThread() + "执行业务逻辑 ！");
            RedisPoolUtil.del(lockName);
            return true;
        //如果已经被锁定，要考虑死锁的情况：
        } else {
            //先拿到锁的上一个时间即previousValue : get
            String previousValue = RedisPoolUtil.get(lockName);
            if (previousValue != null && Long.parseLong(previousValue) >= System.currentTimeMillis()){
                //获取锁的当前时间currentValue，即getset命令（redisTemplate.getAndSet)
                String currentValue = RedisPoolUtil.getSet(lockName, String.valueOf(lockTime));
                if (currentValue != null && currentValue.equals(previousValue)){
                    System.out.println(Thread.currentThread() + "加锁成功！");
                    RedisPoolUtil.expire(lockName, 5);
                    System.out.println(Thread.currentThread() + "执行业务逻辑！");
                    RedisPoolUtil.del(lockName);
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}
